/*===========================================================================
  Copyright (C) 2014 by the Okapi Framework contributors
-----------------------------------------------------------------------------
  This library is free software; you can redistribute it and/or modify it 
  under the terms of the GNU Lesser General Public License as published by 
  the Free Software Foundation; either version 2.1 of the License, or (at 
  your option) any later version.

  This library is distributed in the hope that it will be useful, but 
  WITHOUT ANY WARRANTY; without even the implied warranty of 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
  General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License 
  along with this library; if not, write to the Free Software Foundation, 
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

  See also the full LGPL text here: http://www.gnu.org/copyleft/lesser.html
===========================================================================*/

package net.sf.okapi.v2.common.om.impl;

import java.util.concurrent.ConcurrentHashMap;

import net.sf.okapi.v2.common.LocaleId;
import net.sf.okapi.v2.common.om.IStore;
import net.sf.okapi.v2.common.om.ITag;
import net.sf.okapi.v2.common.om.ITags;
import net.sf.okapi.v2.common.om.ITextContainer;
import net.sf.okapi.v2.common.om.IWithStore;

/**
 * Implements {@link IStore}.
 */
public class Store implements IStore {

	private IWithStore parent;
	private ITags source;
	private ConcurrentHashMap<LocaleId, ITags> targets;
	private int lastSuggested;
	private int lastSegSuggested;
	
	public Store (IWithStore parent) {
		this.parent = parent;
	}
	
	@Override
	public IWithStore getParent () {
		return parent;
	}

	/**
	 * Registers a given {@link ITextContainer} with this store.
	 * @param container the container to register.
	 * @param locId the target locale id corresponding to the text container, or null for the source locale.
	 */
	public void register (ITextContainer container,
		LocaleId locId)
	{
		if ( locId == null ) {
			source = container.getTags();
		}
		else {
			if ( targets == null ) targets = new ConcurrentHashMap<>(1);
			targets.put(locId, container.getTags());
		}
	}
	
	/**
	 * Unregisters a {@link ITags} for a given locale.
	 * @param locId the locale to unregister: use null for the source.
	 */
	public void unregister (LocaleId locId) {
		if ( locId == null ) {
			source = null;
		}
		else {
			if ( targets != null ) {
				ITags tags = targets.get(locId);
				if ( tags != null ) {
					targets.remove(locId);
				}
			}
		}
	}
	
	@Override
	public boolean hasSourceTag () {
		if ( source == null ) return false;
		return (source.size() > 0);
	}

	@Override
	public boolean hasTargetTag (LocaleId trgLoc) {
		if ( targets == null ) return false;
		ITags tags = targets.get(trgLoc);
		return (tags.size() > 0);
	}

	@Override
	public ITags getSourceTags () {
		return source;
	}

	@Override
	public ITags getTargetTags (LocaleId trgLoc) {
		if ( targets == null ) return null;
		return targets.get(trgLoc);
	}

	@Override
	public ITag getFirstTag (String id) {
		if ( source != null ) {
			for ( ITag tag : source ) {
				if ( id.equals(tag.getId()) ) return tag;
			}
		}
		if ( targets == null ) return null;
		for ( ITags tags : targets.values() ) {
			for ( ITag marker : tags ) {
				if ( id.equals(marker.getId()) ) return marker;
			}
		}
		return null;
	}

	/**
	 * Gets a suggested id for code, annotation, ignorable or segment.
	 * @param forSegment true for a segment id, false for other elements.
	 * @return a suggested id which does not exist in this unit.
	 */
	@Override
	public String suggestId (boolean forSegment) {
		String id;
		while ( true ) {
			if ( forSegment ) {
				id = "s"+String.valueOf(++lastSegSuggested);
			}
			else {
				id = String.valueOf(++lastSuggested);
			}
			if ( !parent.isIdUsed(id) ) return id;
			// Else: try another one
		}
	}

}
